package com.gb28181;

import java.io.ByteArrayInputStream;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Vector;

import javax.sdp.Connection;
import javax.sdp.SdpException;
import javax.sdp.Version;
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import javax.sip.DialogTerminatedEvent;
import javax.sip.IOExceptionEvent;
import javax.sip.InvalidArgumentException;
import javax.sip.ListeningPoint;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.SipListener;
import javax.sip.SipProvider;
import javax.sip.TimeoutEvent;
import javax.sip.TransactionAlreadyExistsException;
import javax.sip.TransactionDoesNotExistException;
import javax.sip.TransactionTerminatedEvent;
import javax.sip.TransactionUnavailableException;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.address.URI;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.Header;
import javax.sip.header.HeaderFactory;
import javax.sip.header.MaxForwardsHeader;
import javax.sip.header.ToHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.util.StringUtils;

import com.gb28181.bean.Device;
import com.gb28181.bean.Channel;
import com.gb28181.commons.DigestServerAuthenticationHelper;
import com.gb28181.commons.PtzCmdHelper;

import gov.nist.javax.sdp.MediaDescriptionImpl;
import gov.nist.javax.sdp.SessionDescriptionImpl;
import gov.nist.javax.sdp.TimeDescriptionImpl;
import gov.nist.javax.sdp.fields.AttributeField;
import gov.nist.javax.sdp.fields.ConnectionField;
import gov.nist.javax.sdp.fields.MediaField;
import gov.nist.javax.sdp.fields.OriginField;
import gov.nist.javax.sdp.fields.ProtoVersionField;
import gov.nist.javax.sdp.fields.SessionNameField;
import gov.nist.javax.sdp.fields.TimeField;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires;

public class SipLayer implements SipListener {
	
	String sipIp;
	Integer sipPort;
	String sipDeviceId;
	String sipDomain;
	String sipPassword;
	String mediaIp;
	Integer mediaRtpPort;

	private SipStackImpl sipStack;
	private AddressFactory addressFactory;
	private HeaderFactory headerFactory;
	private MessageFactory messageFactory;
	private SipProvider tcpSipProvider;
	private SipProvider udpSipProvider;

	/************************************************************/

	public SipLayer(String sipIp, Integer sipPort, String sipDeviceId, String sipDomain, String sipPassword,String mediaIp,Integer mediaRtpPort) {
		this.sipIp = sipIp;
		this.sipPort = sipPort;
		this.sipDeviceId = sipDeviceId;
		this.sipDomain = sipDomain;
		this.sipPassword = sipPassword;
		this.mediaIp = mediaIp;
		this.mediaRtpPort = mediaRtpPort;
	}

	public boolean startServer() {
		return initSip();
	}

	private boolean initSip() {
		try {
			SipFactory sipFactory = SipFactory.getInstance();
			Properties properties = new Properties();
			properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
			properties.setProperty("javax.sip.IP_ADDRESS", sipIp);
			sipStack = (SipStackImpl) sipFactory.createSipStack(properties);

			headerFactory = sipFactory.createHeaderFactory();
			addressFactory = sipFactory.createAddressFactory();
			messageFactory = sipFactory.createMessageFactory();
			// 同时监听UDP和TCP
			try {
				ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(sipIp, sipPort, "TCP");

				ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipIp, sipPort, "UDP");

				tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
				tcpSipProvider.addSipListener(this);

				udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
				udpSipProvider.addSipListener(this);
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	/************************************************************/

	@Override
	public void processRequest(RequestEvent requestEvent) {
		Request request = requestEvent.getRequest();
		String method = request.getMethod();
		if (method.equalsIgnoreCase(Request.REGISTER)) {
			processRequestRegister(requestEvent);
		}
		if (method.equalsIgnoreCase(Request.MESSAGE) && new String(request.getRawContent()).contains("<CmdType>Catalog</CmdType>")) {
			processRequestCatalogList(requestEvent);
		}
		if (method.equalsIgnoreCase(Request.MESSAGE) && new String(request.getRawContent()).contains("<CmdType>Keepalive</CmdType>")) {
			processRequestKeepAlive(requestEvent);
		}
	}

	@Override
	public void processResponse(ResponseEvent responseEvent) {
		Response response = responseEvent.getResponse();
		CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
		String method = cseqHeader.getMethod();
		int status = response.getStatusCode();
		if ((status >= 200) && (status < 300)) { // Success!
			if(Request.INVITE.equals(method)){
				processResponseAck(responseEvent);
			}
		}
		//trying不会回复
		if(status == Response.TRYING){

		}
	}

	@Override
	public void processTimeout(TimeoutEvent timeoutEvent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void processIOException(IOExceptionEvent exceptionEvent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
		// TODO Auto-generated method stub

	}

	@Override
	public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
		// TODO Auto-generated method stub

	}

	/************************************************************/
	/***
	 * 收到注册请求 处理
	 */
	public void processRequestRegister(RequestEvent evt) {
		try {
			Request request = evt.getRequest();
			ServerTransaction serverTransaction = evt.getServerTransaction();
			// 判断TCP还是UDP
			boolean isTcp = false;
			ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
			String transport = reqViaHeader.getTransport();
			if (transport.equals("TCP")) {
				isTcp = true;
			}
			/**
			 * if(protocol.equals("UDP")) { isTcp = false; }
			 **/
			//
			if (serverTransaction == null) {
				if (isTcp) {
					serverTransaction = tcpSipProvider.getNewServerTransaction(request);
				} else {
					serverTransaction = udpSipProvider.getNewServerTransaction(request);
				}
			}
			//
			Response response = null;
			boolean passwordCorrect = false;
			boolean isRegisterSuceess = false;
			Device device = null;
			Header header = request.getHeader(AuthorizationHeader.NAME);
			// 携带授权头
			// 校验密码是否正确
			if (header != null) {
				passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
						sipPassword);
				if (!passwordCorrect) {
					System.out.println("密码错误");
				}
			}

			// 未携带授权头或者密码错误 回复401
			if (header == null || !passwordCorrect) {
				response = messageFactory.createResponse(Response.UNAUTHORIZED, request);
				new DigestServerAuthenticationHelper().generateChallenge(headerFactory, response, sipDomain);
			}
			// 携带授权头并且密码正确
			else if (header != null && passwordCorrect) {
				response = messageFactory.createResponse(Response.OK, request);
				// 添加date头
				response.addHeader(headerFactory.createDateHeader(Calendar.getInstance(Locale.ENGLISH)));
				ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
				// 添加Contact头
				response.addHeader(request.getHeader(ContactHeader.NAME));
				// 添加Expires头
				response.addHeader(request.getExpires());
				// 注销成功
				if (expiresHeader != null && expiresHeader.getExpires() == 0) {

				}
				// 注册成功
				else {
					isRegisterSuceess = true;
					// 1.获取到通信地址等信息，保存到Redis
					FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
					ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
					String received = viaHeader.getReceived();
					int rPort = viaHeader.getRPort();
					// 本地模拟设备 received 为空 rPort 为 -1
					// 解析本地地址替代
					if (StringUtils.isEmpty(received) || rPort == -1) {
						received = viaHeader.getHost();
						rPort = viaHeader.getPort();
					}
					//
					AddressImpl address = (AddressImpl) fromHeader.getAddress();
					SipUri uri = (SipUri) address.getURI();
					String deviceId = uri.getUser();
					device = new Device();
					device.setDeviceId(deviceId);
					device.setIp(received);
					device.setPort(rPort);
					device.setAddress(received.concat(":").concat(String.valueOf(rPort)));
					device.setTransport(isTcp ? "TCP" : "UDP");
				}
			}
			serverTransaction.sendResponse(response);
			// 注册成功
			// 保存到redis
			// 下发catelog查询目录
			if (isRegisterSuceess && device != null) {
				// RedisUtil.set(device.getDeviceId(), RedisUtil.EXPIRE,
				// JSONObject.toJSONString(device));
				DeviceMap.deviceMap.put(device.getDeviceId(), device);
				//RedisUtil.set(device.getDeviceId(), JSONObject.toJSONString(device), 180);
				TransmitRequestCatalog(device);
			}
		} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
			e.printStackTrace();
		}
	}
	/***
	 * 收到keepalive请求 处理
	 * @param evt
	 */
	public void processRequestKeepAlive(RequestEvent evt){
		try {
			Request request = evt.getRequest();
			Response response = messageFactory.createResponse(Response.OK,request);
			ServerTransaction serverTransaction = evt.getServerTransaction();
			if(serverTransaction == null){
				ViaHeader viaHeader = (ViaHeader)request.getHeader(ViaHeader.NAME);
				String transport = viaHeader.getTransport();
				if(transport.equals("TCP")) {
					serverTransaction = tcpSipProvider.getNewServerTransaction(request);
				}
				if(transport.equals("UDP")) {
					serverTransaction = udpSipProvider.getNewServerTransaction(request);
				}
				
				SAXReader reader = new SAXReader();
				Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
				// reader.setEncoding("GB2312");
				Element rootElement = xml.getRootElement();
				Element deviceIdElement = rootElement.element("DeviceID");
				//更新key时间
				DeviceMap.deviceMap.put(deviceIdElement.getText(), DeviceMap.deviceMap.get(deviceIdElement.getText()));
			}
			serverTransaction.sendResponse(response);
		} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
			e.printStackTrace();
		}
	}
	/***
	 * ack
	 * @param evt
	 */
	public void processResponseAck(ResponseEvent evt) {
		try {
			
			FromHeader form =  (FromHeader) evt.getResponse().getHeader(FromHeader.NAME);
			String[] strs = form.getTag().split("\\_");
			
			Dialog dialog = evt.getDialog();
			DeviceMap.liveDialogMap.put(strs[0]+"_"+strs[1], dialog);
			Request reqAck =dialog.createAck(1L);
			dialog.sendAck(reqAck);
		} catch (InvalidArgumentException | SipException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/***
	 * 收到catalog目录列表请求 处理
	 * @param evt
	 */
	public void processRequestCatalogList(RequestEvent evt) {
		try {
			Request request = evt.getRequest();
			SAXReader reader = new SAXReader();
			// reader.setEncoding("GB2312");
			Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
			Element rootElement = xml.getRootElement();
			Element deviceIdElement = rootElement.element("DeviceID");
			String deviceId = deviceIdElement.getText().toString();
			Element deviceListElement = rootElement.element("DeviceList");
			if (deviceListElement == null) {
				return;
			}
			Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
			if (deviceListIterator != null) {
				Device device = DeviceMap.deviceMap.get(deviceId);
				if(device == null) {
					return;
				}
				Map<String, Channel> channelMap = device.getChannelMap();
				if (channelMap == null) {
					channelMap = new HashMap<String, Channel>(5);
					device.setChannelMap(channelMap);
				}
				// 遍历DeviceList
				while (deviceListIterator.hasNext()) {
					Element itemDevice = deviceListIterator.next();
					Element channelDeviceElement = itemDevice.element("DeviceID");
					if (channelDeviceElement == null) {
						continue;
					}
					String channelDeviceId = channelDeviceElement.getText().toString();
					Element channdelNameElement = itemDevice.element("Name");
					String channelName = channdelNameElement != null ? channdelNameElement.getText().toString() : "";
					Element statusElement = itemDevice.element("Status");
					String status = statusElement != null ? statusElement.getText().toString() : "ON";
					Channel deviceChannel = channelMap.containsKey(channelDeviceId) ? channelMap.get(channelDeviceId) : new Channel();
					deviceChannel.setName(channelName);
					deviceChannel.setChannelId(channelDeviceId);
					if(status.equals("ON")) {
						deviceChannel.setStatus(1);
					}
					if(status.equals("OFF")) {
						deviceChannel.setStatus(0);
					}
					channelMap.put(channelDeviceId, deviceChannel);
				}
				// 更新Redis
				DeviceMap.deviceMap.put(deviceId, DeviceMap.deviceMap.get(deviceId));
			}
		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}
	/***
	 * 云台控制
	 */
	public void TransmitRequestPtz(String deviceId,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) {
		try {
			Device device = DeviceMap.deviceMap.get(deviceId);
			if(device == null) {
				return;
			}
			//sipuri
			SipURI requestURI = addressFactory.createSipURI(deviceId, device.getAddress());
			//via
			ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
			ViaHeader viaHeader = headerFactory.createViaHeader(sipIp, sipPort, device.getTransport(), "ViaPtzBranch");
			viaHeaders.add(viaHeader);
			//from
			SipURI fromSipURI = addressFactory.createSipURI(sipDeviceId,sipIp+":"+sipPort);
			Address fromAddress = addressFactory.createAddress(fromSipURI);
			FromHeader fromHeader = headerFactory.createFromHeader(fromAddress,"FromPtzTag");
			//to
			SipURI toSipURI = addressFactory.createSipURI(deviceId,device.getAddress()); 
			Address toAddress = addressFactory.createAddress(toSipURI);
			ToHeader toHeader = headerFactory.createToHeader(toAddress,"ToPtzTag");
			//callid
			CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
					: udpSipProvider.getNewCallId();
			//Forwards
			MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
			//ceq
			CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.MESSAGE);
			  
			Request request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
			
			String ptzXml = "<?xml version=\"1.0\" ?>" +
                    "<Control>" +
                    "<CmdType>DeviceControl</CmdType>" +
                    "<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>" +
                    "<DeviceID>" + channelId + "</DeviceID>" +
                    "<PTZCmd>" + PtzCmdHelper.create(leftRight, upDown, inOut, moveSpeed, zoomSpeed) + "</PTZCmd>" +
                    "<Info>" +
                    //"<ControlPriority>" + ptzInfo.getPriority() + "</ControlPriority>" +
                    "</Info>" +
                    "</Control>";
			//
			ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("Application", "MANSCDP+xml");
			
			request.setContent(ptzXml, contentTypeHeader);
			
			/**
			ClientTransaction clientTransaction = null;
			if(device.getProtocol().equals("TCP")) {
				clientTransaction = tcpSipProvider.getNewClientTransaction(request);
			}
			if(device.getProtocol().equals("UDP")) {
				clientTransaction = udpSipProvider.getNewClientTransaction(request);
			}
			clientTransaction.sendRequest();
			**/
			if(device.getTransport().equals("TCP")) {
				tcpSipProvider.sendRequest(request);
			}
			if(device.getTransport().equals("UDP")) {
				udpSipProvider.sendRequest(request);
			}
		} catch (SipException | ParseException | InvalidArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
	/***
	 * 请求直播视频流
	 * @param device
	 */
	public String TransmitRequestInvite(String deviceId,String channelId){
		try {
			Device device = DeviceMap.deviceMap.get(deviceId);
			if(device == null) {
				return "";
			}
			//请求行
			SipURI requestLine = addressFactory.createSipURI(channelId, device.getAddress());
			//via
			ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
			ViaHeader viaHeader = headerFactory.createViaHeader(sipIp, sipPort, device.getTransport(), null);
			viaHeader.setRPort();
			viaHeaders.add(viaHeader);
			//from
			SipURI fromSipURI = addressFactory.createSipURI(sipDeviceId,sipIp+":"+sipPort);
			Address fromAddress = addressFactory.createAddress(fromSipURI);
			FromHeader fromHeader = headerFactory.createFromHeader(fromAddress, deviceId+"_"+channelId); //必须要有标记，否则无法创建会话，无法回应ack
			//to
			SipURI toSipURI = addressFactory.createSipURI(channelId,device.getAddress()); 
			Address toAddress = addressFactory.createAddress(toSipURI);
			ToHeader toHeader = headerFactory.createToHeader(toAddress,null);

			//callid
			CallIdHeader callIdHeader = null;
			if(device.getTransport().equals("TCP")) {
				callIdHeader = tcpSipProvider.getNewCallId();
			}
			if(device.getTransport().equals("UDP")) {
				callIdHeader = udpSipProvider.getNewCallId();
			}
			//Forwards
			MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
			//ceq
			CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.INVITE);
			Request request = messageFactory.createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
			ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("Application", "SDP");
			
			
			/***
			 * ssrc
			 * 第1位 0-直播 1-回放
			 * 第2-6位 取20位sip域的4-8位
			 * 第7-10位 取channelId后3位
			 */
			String ssrc = "0"+deviceId.substring(3,9)+channelId.substring(channelId.length()-3,channelId.length());
			//String ssrc = "02000"+deviceId.substring(deviceId.length()-4,deviceId.length());
			StringBuffer content = new StringBuffer(200);
	        content.append("v=0\r\n");
	        content.append("o="+channelId+" 0 0 IN IP4 "+sipIp+"\r\n");
	        content.append("s=Play\r\n");
	        content.append("c=IN IP4 "+mediaIp+"\r\n");
	        content.append("t=0 0\r\n");
	        if(device.getTransport().equals("TCP")) {
	        	content.append("m=video "+mediaRtpPort+" TCP/RTP/AVP 96 98 97\r\n");
			}
	        if(device.getTransport().equals("UDP")) {
	        	content.append("m=video "+mediaRtpPort+" RTP/AVP 96 98 97\r\n");
			}
	        content.append("a=sendrecv\r\n");
	        content.append("a=rtpmap:96 PS/90000\r\n");
	        content.append("a=rtpmap:98 H264/90000\r\n");
	        content.append("a=rtpmap:97 MPEG4/90000\r\n");
	        if(device.getTransport().equals("TCP")){
	             content.append("a=setup:passive\r\n");
	             content.append("a=connection:new\r\n");
	        }
	        content.append("y="+ssrc+"\r\n");//ssrc
	        
	        /**sdp
	        SessionDescriptionImpl session = new SessionDescriptionImpl();
			Version version = new ProtoVersionField();
			version.setVersion(0);
			session.setVersion(version);

			OriginField origin = new OriginField();
			origin.setAddress(device.getHost().getIp());
			origin.setUsername(channelId);
			origin.setSessionId(0);
			origin.setSessionVersion(0);
			origin.setAddressType("IP4");
			origin.setNettype("IN");
			session.setOrigin(origin);

			SessionNameField nameField = new SessionNameField();
			nameField.setSessionName("Play");
			session.setSessionName(nameField);

			Connection connect = new ConnectionField();
			connect.setAddress(mediaIp);
			// connect.setAddress("192.168.3.88");
			connect.setAddressType("IP4");
			connect.setNetworkType("IN");
			session.setConnection(connect);
			TimeDescriptionImpl impl = new TimeDescriptionImpl();
			//Vector<String> RepeatTime = new Vector<>();
			//RepeatField field = new RepeatField();

			// impl.setRepeatTimes(RepeatTime);
			TimeField timeField = new TimeField();
			timeField.setStartTime(0);
			timeField.setStopTime(0);
			impl.setTime(timeField);
			Vector<Object> vector = new Vector<>();
			vector.add(impl);
			session.setTimeDescriptions(vector);

			MediaDescriptionImpl mediaDescriptionImpl = new MediaDescriptionImpl();
			MediaField mediaField = new MediaField();
			mediaField.setMediaType("video");
			mediaField.setPort(mediaPort);
			mediaField.setProtocol("RTP/AVP");
			Vector<Object> mediaFormat = new Vector<>();
			mediaFormat.add("96");
			mediaFormat.add("97");
			mediaFormat.add("98");
			mediaField.setMediaFormats(mediaFormat);
			mediaDescriptionImpl.setMedia(mediaField);
			Vector<Object> vector2 = new Vector<>();
			vector2.add(mediaDescriptionImpl);
			session.setMediaDescriptions(vector2);
			Vector<AttributeField> v3 = new Vector<>();
			AttributeField a1 = new AttributeField();
			a1.setValue("recvonly");
			v3.add(a1);
			AttributeField a2 = new AttributeField();
			a2.setValue("rtpmap:96 PS/90000");
			v3.add(a2);
			AttributeField a3 = new AttributeField();
			a3.setValue("rtpmap:98 H264/90000");
			v3.add(a3);
			AttributeField a4 = new AttributeField();
			a4.setValue("rtpmap:97 MPEG4/90000");
			v3.add(a4);
			mediaDescriptionImpl.setAttributes(v3);
	        **/
	        
	        request.setContent(content.toString(), contentTypeHeader);
	        
	        /** contact
 			SipURI contactURI = addressFactory.createSipURI(sipDeviceId, sipIp + ":" + sipPort);
 			contactURI.setPort(sipPort);
 			contactURI.setHost(sipIp);
 			contactURI.setUser(sipDeviceId);
 			Address contactAddress = addressFactory.createAddress(contactURI);
 			ContactHeader contactHeader = headerFactory.createContactHeader(contactAddress);
 			request.addHeader(contactHeader);
	        **/
			/**ClientTransaction clientTransaction = null;
			if(device.getProtocol().equals("TCP")) {
				clientTransaction = tcpSipProvider.getNewClientTransaction(request);
			}
			if(device.getProtocol().equals("UDP")) {
				clientTransaction = udpSipProvider.getNewClientTransaction(request);
			}
			clientTransaction.sendRequest();**/
 			if(device.getTransport().equals("TCP")) {
				tcpSipProvider.sendRequest(request);
			}
			if(device.getTransport().equals("UDP")) {
				udpSipProvider.sendRequest(request);
			}
			return ssrc;
		} catch ( SipException | ParseException | InvalidArgumentException e) {
			e.printStackTrace();
			return null;
		} 
	}
	/***
	 * 停止视频推流
	 */
	public void TransmitRequestBye(String deviceId,String channelId) {
		try {
			Device device = DeviceMap.deviceMap.get(deviceId);
			if(device == null) {
				return;
			}
			Dialog d = DeviceMap.liveDialogMap.get(deviceId+"_"+channelId);
			if(d!=null) {
				DeviceMap.liveDialogMap.remove(deviceId+"_"+channelId);
			}
			Request byeRequest = d.createRequest(Request.BYE);
			ClientTransaction clientTransaction = null;
			if(device.getTransport().equals("TCP")) {
				clientTransaction = tcpSipProvider.getNewClientTransaction(byeRequest);
			}
			if(device.getTransport().equals("UDP")) {
				clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
			}
			d.sendRequest(clientTransaction);
		} catch (SipException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	/***
	 * 请求目录列表
	 * @param device
	 */
	private void TransmitRequestCatalog(Device device) {
		try {
			String deviceId = device.getDeviceId();
			//sipuri
			SipURI requestURI = addressFactory.createSipURI(deviceId, device.getAddress());
			//via
			ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
			ViaHeader viaHeader = headerFactory.createViaHeader(sipIp, sipPort, device.getTransport(), "ViaCatalogBranch");
			viaHeaders.add(viaHeader);
			//from
			SipURI fromSipURI = addressFactory.createSipURI(sipDeviceId,sipIp+":"+sipPort);
			Address fromAddress = addressFactory.createAddress(fromSipURI);
			FromHeader fromHeader = headerFactory.createFromHeader(fromAddress,"FromCatalogTag");
			//to
			SipURI toSipURI = addressFactory.createSipURI(deviceId,device.getAddress()); 
			Address toAddress = addressFactory.createAddress(toSipURI);
			ToHeader toHeader = headerFactory.createToHeader(toAddress,"ToCatalogTag");
			//callid
			CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
					: udpSipProvider.getNewCallId();
			//Forwards
			MaxForwardsHeader maxForwards = headerFactory.createMaxForwardsHeader(70);
			//ceq
			CSeqHeader cSeqHeader = headerFactory.createCSeqHeader(1L, Request.MESSAGE);
			  
			Request request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
			
			StringBuffer catalogXml = new StringBuffer(200);
			catalogXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\n");
			catalogXml.append("<Query>\n");
			catalogXml.append("<CmdType>Catalog</CmdType>\n");
			catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\n");
			catalogXml.append("<DeviceID>" + deviceId + "</DeviceID>\n");
			catalogXml.append("</Query>\n");
			
			//
			ContentTypeHeader contentTypeHeader = headerFactory.createContentTypeHeader("Application", "MANSCDP+xml");
			
			request.setContent(catalogXml, contentTypeHeader);
			
			/**
			ClientTransaction clientTransaction = null;
			if(device.getProtocol().equals("TCP")) {
				clientTransaction = tcpSipProvider.getNewClientTransaction(request);
			}
			if(device.getProtocol().equals("UDP")) {
				clientTransaction = udpSipProvider.getNewClientTransaction(request);
			}
			clientTransaction.sendRequest();
			**/
			if(device.getTransport().equals("TCP")) {
				tcpSipProvider.sendRequest(request);
			}
			if(device.getTransport().equals("UDP")) {
				udpSipProvider.sendRequest(request);
			}
		} catch (SipException | ParseException | InvalidArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	/*****************************************************************************/

}
